#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <stdexcept>

/*
  Public interface of the MySQL Connector/C++.
  You might not use it but directly include directly the different
  headers from cppconn/ and mysql_driver.h + mysql_util.h
  (and mysql_connection.h). This will reduce your build time!
*/
#include <driver/mysql_public_iface.h>
/* Connection parameter and sample data */
#include "examples.h"
#include "UF8.h"

#define EXAMPLE_QUERY_1 "SELECT products, no, price, flag FROM test"
#define EXAMPLE_QUERY_2 "SELECT product FROM products ORDER BY product ASC"

using namespace std;

static GtkWidget *window = NULL;
static GtkWidget *entry1 = NULL;
static GtkWidget *entry2 = NULL;

typedef struct
{
  gchar* product;
}
Prod;

enum
{
  COLUMN_PRODUCT_TEXT,
  NUM_PRODUCT_COLUMNS
};

static GArray *products = NULL;

sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;

stringstream sql_str;
int counter=0;

char find_str[100];
int find_no=-1;
int find_idx=-1;

GtkWidget *treeview;
GtkTreeModel *items_model;
GtkTreeModel *products_model;
GtkWidget *vbox;
GtkWidget *sw;

string fld_arr[20];
string tbl_name;
gint fld_cnt=0;
GType TypeArr[20];

void del_space(string &s)
{
	  for (size_t i = 0; i < s.length(); i++) {
	      if ((s[i] == ' ') || (s[i] == '\n') || (s[i] == '\t'))
	      {
	          s.erase(i, 1);
	          i--;
	      }
	  }
}

void fld_extract()
{
	for(int i=0;i<fld_cnt;i++)
		fld_arr[i].clear();

	fld_cnt=0;

	size_t pos, pos_sel, pos_frm, pos_whr;
	  std::string s1 = gtk_entry_get_text (GTK_ENTRY (entry1));

	  if (s1.find("SELECT")!= std::string::npos) pos_sel=s1.find("SELECT");
	  else if ((s1.find("select")!= std::string::npos)) pos_sel=s1.find("select");
	  else
	  {
	  	std::cout<<"Please insert a valid SQL statement!"<<std::endl;
	  	pos_sel=0;
	  }

	  if (s1.find("FROM")!= std::string::npos) pos_frm=s1.find("FROM");
	  else if ((s1.find("from")!= std::string::npos)) pos_frm=s1.find("from");
	  else
	  {
	  	std::cout<<"Please insert a valid SQL statement!"<<std::endl;
	  	pos_frm=0;
	  }

	  if (s1.find("WHERE")!= std::string::npos) pos_whr=s1.find("WHERE");
	  else if ((s1.find("where")!= std::string::npos)) pos_whr=s1.find("where");
	  else
	  {
	  	 pos_whr=s1.length();
	  }


	  std::string s = s1.substr(pos_sel, pos_frm);
	  tbl_name=s1.substr(pos_frm+5, pos_whr-s.length());
	  del_space(tbl_name);

	  s.erase(0,7);

	  del_space(s);

	  std::string delimiter = ",";

	  pos = 0;
	  std::string token;

	  while ((pos = s.find(delimiter)) != std::string::npos) {
	      token = s.substr(0, pos);
	  	  fld_arr[fld_cnt++] = token;
	      s.erase(0, pos + delimiter.length());
	  }
	  fld_arr[fld_cnt]=s;
}

void types_extract()
{
	  for(int i=0;i<fld_cnt;i++)
		  TypeArr[i]=0;

	  for(int i=0;i<=fld_cnt;i++)
	  {
		  string str="SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '";
		  str.append(tbl_name);
		  str.append("' AND COLUMN_NAME = '");
		  str.append(fld_arr[i]);
		  str.append("';");

			res = stmt->executeQuery(str);
			  if(res->next())
			  {
				if(strncmp("char",res->getString(1).c_str(),4)==0)
					TypeArr[i]=G_TYPE_STRING;
				else if (strncmp("int",res->getString(1).c_str(),3)==0)
					TypeArr[i]=G_TYPE_INT;
				else if (strncmp("tinyint",res->getString(1).c_str(),7)==0)
					TypeArr[i]=G_TYPE_BOOLEAN;
			  }
	  }
}

gboolean
  foreach_func (GtkTreeModel *model,
                GtkTreePath  *path,
                GtkTreeIter  *iter,
                gpointer      user_data)
  {
    gboolean _bool;
	gchar *_string;
    gint  _number;

    /* Note: here we use 'iter' and not '&iter', because we did not allocate
     *  the iter on the stack and are already getting the pointer to a tree iter */

    gtk_tree_model_get_iter (model, iter, path);

	sql_str.str("");
	sql_str << "INSERT INTO "<< tbl_name << "(";

    for(int i=0;i<=fld_cnt;i++)
    {
    	sql_str << fld_arr[i];
    	if (i!=fld_cnt) sql_str << ", ";
    }

    sql_str << ") VALUES (";

    for(int i=0;i<=fld_cnt;i++)
    {
		  if (TypeArr[i]==G_TYPE_STRING)
		  {
			  gtk_tree_model_get (model, iter, i, &_string, -1);
			  sql_str << "'" << _string << "'";
		  }
		  else if (TypeArr[i]==G_TYPE_INT)
		  {
			  gtk_tree_model_get (model, iter, i, &_number, -1);
			  sql_str << _number;
		  }
		  else if (TypeArr[i]==G_TYPE_BOOLEAN)
		  {
			  gtk_tree_model_get (model, iter, i, &_bool, -1);
			  sql_str << _bool;
		  }
		  if(i!=fld_cnt) sql_str << ",";
    }
	sql_str << ")";

	cout<<sql_str.str()<<endl;

	stmt->execute(sql_str.str());

    g_free(_string); /* gtk_tree_model_get made copies of       */
    /* the strings for us when retrieving them */

    return FALSE; /* do not stop walking the store, call us with next row */
  }

static void
add_products ()
{
	stringstream msg;

	try {
			/*
			Run a query which returns exactly one result set like SELECT
			Stored procedures (CALL) may return more than one result set
			*/
			res = stmt->executeQuery(gtk_entry_get_text (GTK_ENTRY (entry2)));

			/* Fetching data */
			Prod prod;
			g_return_if_fail (products != NULL);
			while (res->next()) {
				prod.product=WChar_to_UTF8(GetWC(res->getString(1).c_str()));
				g_array_append_vals (products, &prod, 1);
			}
	} catch (sql::SQLException &e) {
		/*
		The MySQL Connector/C++ throws three different exceptions:

		- sql::MethodNotImplementedException (derived from sql::SQLException)
		- sql::InvalidArgumentException (derived from sql::SQLException)
		- sql::SQLException (derived from std::runtime_error)
		*/
		cout << "\n# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cout << "\n# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;
		cout << "not ok 1 - examples/connect.php" << endl;

	} catch (std::runtime_error &e) {

		cout << "\n# ERR: runtime_error in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		cout << "\n# ERR: " << e.what() << endl;
		cout << "not ok 1 - examples/connect.php" << endl;

	}
}

static GtkTreeModel *
create_items_model (void)
{
  gint i = 0;
  GtkListStore *model;
  GtkTreeIter iter;

  fld_extract();

  types_extract();

  /* create list store */

  model = gtk_list_store_newv (fld_cnt+1, TypeArr);

  /* add items */
  res = stmt->executeQuery(gtk_entry_get_text (GTK_ENTRY (entry1)));

  counter=res->rowsCount();

  /* Fetching data */
  while (res->next())
  {
      gtk_list_store_append (model, &iter);
      for(i=0;i<=fld_cnt;i++)
      {
		  if (TypeArr[i]==G_TYPE_STRING) gtk_list_store_set (model, &iter, i, WChar_to_UTF8(GetWC(res->getString(i+1).c_str())), -1);
		  else if (TypeArr[i]==G_TYPE_INT) gtk_list_store_set (model, &iter, i, res->getInt(i+1), -1);
		  else if (TypeArr[i]==G_TYPE_BOOLEAN) gtk_list_store_set (model, &iter, i, res->getBoolean(i+1), -1);
      }
   }
  return GTK_TREE_MODEL (model);
}

static GtkTreeModel *
create_products_model (void)
{
  gint i = 0;
  GtkListStore *model;
  GtkTreeIter iter;

  /* create array */
  products = g_array_sized_new (FALSE, FALSE, sizeof (Prod), 1);

  add_products ();

  /* create list store */
  model = gtk_list_store_new (NUM_PRODUCT_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN);

  /* add products */
  for (i = 0; i < products->len; i++)
    {
      gtk_list_store_append (model, &iter);

      gtk_list_store_set (model, &iter,
    		  	  	  COLUMN_PRODUCT_TEXT,
    		  	  	  g_array_index (products, Prod, i).product,
    		  	  	  -1);
    }

  return GTK_TREE_MODEL (model);

#undef N_NUMBERS
}

void get_iter_last( GtkTreeModel *mdl, GtkTreeIter *itr )
{
  GtkTreeIter i;
  if ( gtk_tree_model_get_iter_first( mdl, &i ) ) {
    while ( gtk_tree_model_iter_next( mdl, &i ) ) {
      *itr = i;
    }
  }
}

static void
add_item (GtkWidget *button, gpointer data)
{
  GtkTreeIter iter;
  GtkTreeModel *model = items_model;

  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
  for(int i=0;i<=fld_cnt;i++)
  {
	  if (TypeArr[i]==G_TYPE_STRING) gtk_list_store_set (GTK_LIST_STORE (model), &iter, i, "***", -1);
	  else if (TypeArr[i]==G_TYPE_INT) gtk_list_store_set (GTK_LIST_STORE (model), &iter, i, 0, -1);
	  else if (TypeArr[i]==G_TYPE_BOOLEAN) gtk_list_store_set (GTK_LIST_STORE (model), &iter, i, FALSE, -1);
  }
}

static void
remove_item (GtkWidget *widget, gpointer data)
{
  GtkTreeIter iter;
  GtkTreeView *tree = (GtkTreeView *)treeview;
  GtkTreeModel *model = items_model;
  GtkTreeSelection *selection = gtk_tree_view_get_selection (tree);
  get_iter_last(model, &iter);

  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
    {
      GtkTreePath *path;

      path = gtk_tree_model_get_path (model, &iter);

	  gtk_list_store_remove (GTK_LIST_STORE (model), &iter);

	  gtk_tree_path_free (path);

	  counter--;
   }
}

static gboolean
separator_row (GtkTreeModel *model,
               GtkTreeIter  *iter,
               gpointer      data)
{
  GtkTreePath *path;
  gint idx;

  path = gtk_tree_model_get_path (model, iter);
  idx = gtk_tree_path_get_indices (path)[0];

  gtk_tree_path_free (path);

  return idx == 5;
}

static void
editing_started (GtkCellRenderer *cell,
                 GtkCellEditable *editable,
                 const gchar     *path,
                 gpointer         data)
{
  gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (editable),
                                        separator_row, NULL, NULL);
}

static void
cell_edited (GtkCellRendererText *cell,
             const gchar         *path_string,
             const gchar         *new_text,
             gpointer             data)
{
  GtkTreeModel *model = (GtkTreeModel *)data;
  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
  GtkTreeIter iter;

  gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));

  gtk_tree_model_get_iter (model, &iter, path);

	  if (TypeArr[column]==G_TYPE_STRING)
	  {
	      gchar *old_text;
	      gtk_tree_model_get (model, &iter, column, &old_text, -1);
	      g_free (old_text);
		  gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, g_strdup (new_text), -1);
	  }
	  else if (TypeArr[column]==G_TYPE_INT) gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, atoi (new_text), -1);

  gtk_tree_path_free (path);
}

static void
fixed_toggled (GtkCellRendererToggle *cell,
               gchar                 *path_str,
               gpointer               data)
{
  GtkTreeModel *model = (GtkTreeModel *)data;
  GtkTreeIter  iter;
  GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
  gboolean fixed;
  gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));;

  /* get toggled iter */
  gtk_tree_model_get_iter (model, &iter, path);
  gtk_tree_model_get (model, &iter, column, &fixed, -1);

  /* do something with the value */
  fixed ^= 1;

  /* set new value */
  gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, fixed, -1);

  /* clean up */
  gtk_tree_path_free (path);
}

static void save_items(GtkWidget *button, gpointer data)
{
	  GtkTreeModel *model = items_model;

	  fld_extract();

	  types_extract();

	  string sql="DELETE FROM ";
	  sql.append(tbl_name);

	  stmt->execute(sql);

	  gtk_tree_model_foreach(GTK_TREE_MODEL(model), foreach_func, NULL);
	  cout << "\n#\t Records saved" << endl;
}

static void
add_columns (GtkTreeView  *treeview,
             GtkTreeModel *items_model,
             GtkTreeModel *products_model)
{
  GtkCellRenderer *renderer;
  GtkTreeViewColumn *column;

  for(int i=0;i<=fld_cnt;i++)
  {
	  if (TypeArr[i]==G_TYPE_STRING)
	  {
		  renderer = gtk_cell_renderer_combo_new ();

		  g_object_set (renderer,
		                "model", products_model,
		                "text-column", COLUMN_PRODUCT_TEXT,
		                "has-entry", TRUE,
		                "editable", TRUE,
		                NULL);
		  g_signal_connect (renderer, "edited",
		                    G_CALLBACK (cell_edited), items_model);
		  g_signal_connect (renderer, "editing-started",
		                    G_CALLBACK (editing_started), NULL);
		  g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (i));
		  column = gtk_tree_view_column_new_with_attributes (fld_arr[i].c_str(),
		                                                     renderer,
		                                                     "text",
		                                                     i,
		                                                     NULL);
		  gtk_tree_view_column_set_sort_column_id (column, i);
		  gtk_tree_view_append_column (treeview, column);
	  }
	  else if (TypeArr[i]==G_TYPE_INT)
	  {
		  renderer = gtk_cell_renderer_text_new ();
		  g_object_set (renderer, "editable", TRUE, NULL);
		  g_signal_connect (renderer, "edited",
							G_CALLBACK (cell_edited), items_model);
		  g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (i));
		  column = gtk_tree_view_column_new_with_attributes (fld_arr[i].c_str(),
															 renderer,
															 "text",
															 i,
															 NULL);
		  gtk_tree_view_column_set_sort_column_id (column, i);
		  gtk_tree_view_append_column (treeview, column);
	  }
	  else if (TypeArr[i]==G_TYPE_BOOLEAN)
	  {
		  renderer = gtk_cell_renderer_toggle_new ();
		  g_signal_connect (renderer, "toggled",
							G_CALLBACK (fixed_toggled), items_model);
		  g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (i));
		  column = gtk_tree_view_column_new_with_attributes (fld_arr[i].c_str(),
															 renderer,
															 "active", i,
															 NULL);

		  /* set this column to a fixed sizing (of 50 pixels) */
		  gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
										   GTK_TREE_VIEW_COLUMN_FIXED);
		  gtk_tree_view_column_set_fixed_width (GTK_TREE_VIEW_COLUMN (column), 50);
		  gtk_tree_view_append_column (treeview, column);
	  }
  }
}

void add_treeview()
{
	if(GTK_IS_WIDGET (treeview)) gtk_container_remove (GTK_CONTAINER (sw), treeview);
	/* create models */
    items_model = create_items_model ();
    products_model = create_products_model ();

    /* create tree view */
    treeview = gtk_tree_view_new_with_model (items_model);
    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
    gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
                                 GTK_SELECTION_SINGLE);

    add_columns (GTK_TREE_VIEW (treeview), items_model, products_model);

    fld_cnt=0;

    g_object_unref (products_model);
    g_object_unref (items_model);

    gtk_container_add (GTK_CONTAINER (sw), treeview);

    gtk_widget_show_all (window);
}

static void
interactive_dialog_clicked (GtkButton *button,
			    gpointer   user_data)
{
  GtkWidget *dialog;
  GtkWidget *hbox;
  GtkWidget *stock;
  GtkWidget *table;
  GtkWidget *local_entry1;
  GtkWidget *local_entry2;
  GtkWidget *label;
  gint response;

  dialog = gtk_dialog_new_with_buttons( "Data source",
                                                GTK_WINDOW( window ),
                                                GTK_DIALOG_MODAL,
                                                GTK_STOCK_YES, 1,
                                                GTK_STOCK_NO,  2,
                                                NULL );

  hbox = gtk_hbox_new (FALSE, 8);
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);

  stock = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
  gtk_box_pack_start (GTK_BOX (hbox), stock, FALSE, FALSE, 0);

  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_row_spacings (GTK_TABLE (table), 4);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
  label = gtk_label_new_with_mnemonic ("_SQL 1");
  gtk_table_attach_defaults (GTK_TABLE (table),
			     label,
			     0, 1, 0, 1);
  local_entry1 = gtk_entry_new ();
  gtk_entry_set_text (GTK_ENTRY (local_entry1), gtk_entry_get_text (GTK_ENTRY (entry1)));
  gtk_table_attach_defaults (GTK_TABLE (table), local_entry1, 1, 2, 0, 1);
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry1);

  label = gtk_label_new_with_mnemonic ("S_QL 2");
  gtk_table_attach_defaults (GTK_TABLE (table),
			     label,
			     0, 1, 1, 2);

  local_entry2 = gtk_entry_new ();
  gtk_entry_set_text (GTK_ENTRY (local_entry2), gtk_entry_get_text (GTK_ENTRY (entry2)));
  gtk_table_attach_defaults (GTK_TABLE (table), local_entry2, 1, 2, 1, 2);
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry2);

  gtk_widget_show_all (hbox);
  response = gtk_dialog_run (GTK_DIALOG (dialog));

  if (response == 1)
    {
      gtk_entry_set_text (GTK_ENTRY (entry1), gtk_entry_get_text (GTK_ENTRY (local_entry1)));
      gtk_entry_set_text (GTK_ENTRY (entry2), gtk_entry_get_text (GTK_ENTRY (local_entry2)));
      add_treeview();
    }

  gtk_widget_destroy (dialog);
}

static void
activate_action (GtkAction *action)
{
  g_message ("Action \"%s\" activated", gtk_action_get_name (action));
  gtk_widget_destroy (window);
}

static void
activate_radio_action (GtkAction *action, GtkRadioAction *current)
{
  g_message ("Radio action \"%s\" selected",
	     gtk_action_get_name (GTK_ACTION (current)));
}

gchar *
demo_find_file (const char *base, GError    **err)
{
g_return_val_if_fail (err == NULL || *err == NULL, NULL);

if (g_file_test ("gtk-logo-rgb.gif", G_FILE_TEST_EXISTS) &&
g_file_test (base, G_FILE_TEST_EXISTS))
return g_strdup (base);
else
{
char *filename = g_build_filename ("C:/MinGW/gtk+/share/gtk-2.0/demo", base, NULL);
if (!g_file_test (filename, G_FILE_TEST_EXISTS))
{
g_set_error (err, G_FILE_ERROR, G_FILE_ERROR_NOENT,
 "Cannot find demo data file \"%s\"", base);
g_free (filename);
return NULL;
}
return filename;
}
}

static void
about_cb (GtkAction *action,
	  GtkWidget *window)
{
  GdkPixbuf *pixbuf, *transparent;
  gchar *filename;

  const gchar *authors[] = {
    "Radu Manea who tries",
    "desperately to show that",
    "impossible is nothing and",
    "above misconceptions and",
    "ignorance there's tones of",
    "hypocrisy...",
    NULL
  };

  const gchar *documentors[] = {
    "Radu Manea who tries",
    "desperately to show that",
    "impossible is nothing and",
    "above misconceptions and",
    "ignorance there's tones of",
    "hypocrisy...",
    NULL
  };

  const gchar *license =
    "This is free software; you can redistribute it and/or\n"
    "modify it under the terms of the GNU Library General Public License as\n"
    "published by the Free Software Foundation; either version 2 of the\n"
    "License, or (at your option) any later version.\n"
    "\n"
    "This library is distributed in the hope that it will be useful,\n"
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
    "Library General Public License for more details.\n"
    "\n"
    "You should have received a copy of the GNU Library General Public\n"
    "License along with the Gnome Library; see the file COPYING.LIB.  If not,\n"
    "write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
    "Boston, MA 02111-1307, USA.\n";

  pixbuf = NULL;
  transparent = NULL;
  filename = demo_find_file ("gtk-logo-rgb.gif", NULL);
  if (filename)
    {
      pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
      g_free (filename);
      transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
      g_object_unref (pixbuf);
    }

  gtk_show_about_dialog (GTK_WINDOW (window),
			 "program-name", "MySQLBrowser",
			 "version", "3.2",
			 "copyright", "(C) 2013 Author",
			 "license", license,
			 "website", "http://mysqlbrowser.codeplex.com/",
			 "comments", "Program to demonstrate GTK+ integration with MySQL CPP connector",
			 "authors", authors,
			 "documenters", documentors,
			 "logo", transparent,
                         "title", "About MySQLBrowser",
			 NULL);

  g_object_unref (transparent);
}

static GtkActionEntry entries[] = {
  { "EditMenu", NULL, "_Edit" },               /* name, stock id, label */
  { "PreferencesMenu", NULL, "_Preferences" }, /* name, stock id, label */
  { "ColorMenu", NULL, "_Color"  },            /* name, stock id, label */
  { "ShapeMenu", NULL, "_Shape" },             /* name, stock id, label */
  { "HelpMenu", NULL, "_Help" },               /* name, stock id, label */
  { "New", GTK_STOCK_NEW,                      /* name, stock id */
    "_New", "<control>N",                      /* label, accelerator */
    "Create a new record",                       /* tooltip */
    G_CALLBACK (add_item) },
  { "Open", GTK_STOCK_OPEN,                    /* name, stock id */
    "_Open","<control>O",                      /* label, accelerator */
    "Open a file",                             /* tooltip */
    G_CALLBACK (interactive_dialog_clicked) },
  { "Save", GTK_STOCK_SAVE,                    /* name, stock id */
    "_Save","<control>S",                      /* label, accelerator */
    "Save current recordset",                       /* tooltip */
    G_CALLBACK (save_items) },
  { "Delete", GTK_STOCK_DELETE,                  /* name, stock id */
    "_Delete","<control>D",                       /* label, accelerator */
    "Delete a record",                          /* tooltip */
    G_CALLBACK (remove_item) },
  { "Quit", GTK_STOCK_QUIT,                    /* name, stock id */
    "_Quit", "<control>Q",                     /* label, accelerator */
    "Quit",                                    /* tooltip */
    G_CALLBACK (activate_action)},
  { "About", NULL,                             /* name, stock id */
    "_About", "<control>A",                    /* label, accelerator */
    "About",                                   /* tooltip */
    G_CALLBACK (about_cb) },
  { "Logo", "demo-gtk-logo",                   /* name, stock id */
     NULL, NULL,                               /* label, accelerator */
    "GTK+",                                    /* tooltip */
    G_CALLBACK (activate_action) },
};
static guint n_entries = G_N_ELEMENTS (entries);


static GtkToggleActionEntry toggle_entries[] = {
  { "Bold", GTK_STOCK_BOLD,                    /* name, stock id */
     "_Bold", "<control>B",                    /* label, accelerator */
    "Bold",                                    /* tooltip */
    G_CALLBACK (activate_action),
    TRUE },                                    /* is_active */
};
static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries);

enum {
  COLOR_RED,
  COLOR_GREEN,
  COLOR_BLUE
};

static GtkRadioActionEntry color_entries[] = {
  { "Red", NULL,                               /* name, stock id */
    "_Red", "<control>R",                      /* label, accelerator */
    "Blood", COLOR_RED },                      /* tooltip, value */
  { "Green", NULL,                             /* name, stock id */
    "_Green", "<control>G",                    /* label, accelerator */
    "Grass", COLOR_GREEN },                    /* tooltip, value */
  { "Blue", NULL,                              /* name, stock id */
    "_Blue", "<control>B",                     /* label, accelerator */
    "Sky", COLOR_BLUE },                       /* tooltip, value */
};
static guint n_color_entries = G_N_ELEMENTS (color_entries);

enum {
  SHAPE_SQUARE,
  SHAPE_RECTANGLE,
  SHAPE_OVAL
};

static GtkRadioActionEntry shape_entries[] = {
  { "Square", NULL,                            /* name, stock id */
    "_Square", "<control>S",                   /* label, accelerator */
    "Square",  SHAPE_SQUARE },                 /* tooltip, value */
  { "Rectangle", NULL,                         /* name, stock id */
    "_Rectangle", "<control>R",                /* label, accelerator */
    "Rectangle", SHAPE_RECTANGLE },            /* tooltip, value */
  { "Oval", NULL,                              /* name, stock id */
    "_Oval", "<control>O",                     /* label, accelerator */
    "Egg", SHAPE_OVAL },                       /* tooltip, value */
};
static guint n_shape_entries = G_N_ELEMENTS (shape_entries);

static const gchar *ui_info =
"<ui>"
"  <menubar name='MenuBar'>"
"    <menu action='EditMenu'>"
"      <menuitem action='New'/>"
"      <menuitem action='Open'/>"
"      <menuitem action='Save'/>"
"      <menuitem action='Delete'/>"
"      <separator/>"
"      <menuitem action='Quit'/>"
"    </menu>"
"    <menu action='PreferencesMenu'>"
"      <menu action='ColorMenu'>"
"	<menuitem action='Red'/>"
"	<menuitem action='Green'/>"
"	<menuitem action='Blue'/>"
"      </menu>"
"      <menu action='ShapeMenu'>"
"        <menuitem action='Square'/>"
"        <menuitem action='Rectangle'/>"
"        <menuitem action='Oval'/>"
"      </menu>"
"      <menuitem action='Bold'/>"
"    </menu>"
"    <menu action='HelpMenu'>"
"      <menuitem action='About'/>"
"    </menu>"
"  </menubar>"
"  <toolbar  name='ToolBar'>"
"    <toolitem action='Open'/>"
"    <toolitem action='Quit'/>"
"    <separator action='Sep1'/>"
"    <toolitem action='Logo'/>"
"  </toolbar>"
"</ui>";

void add_menu()
{
    GtkActionGroup *actions;
    GtkUIManager *ui;
    GError *error = NULL;

    actions = gtk_action_group_new ("Actions");
    gtk_action_group_add_actions (actions, entries, n_entries, NULL);
    gtk_action_group_add_toggle_actions (actions,
         					   toggle_entries, n_toggle_entries,
         					   NULL);
    gtk_action_group_add_radio_actions (actions,
         					  color_entries, n_color_entries,
         					  COLOR_RED,
         					  G_CALLBACK (activate_radio_action),
         					  NULL);
    gtk_action_group_add_radio_actions (actions,
         					  shape_entries, n_shape_entries,
         					  SHAPE_OVAL,
         					  G_CALLBACK (activate_radio_action),
         					  NULL);

    ui = gtk_ui_manager_new ();
    gtk_ui_manager_insert_action_group (ui, actions, 0);
    g_object_unref (actions);
    gtk_window_add_accel_group (GTK_WINDOW (window),
    gtk_ui_manager_get_accel_group (ui));

    if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error))
         	{
         	  g_message ("building menus failed: %s", error->message);
         	  g_error_free (error);
         	}

    gtk_box_pack_start (GTK_BOX (vbox),
         			  gtk_ui_manager_get_widget (ui, "/MenuBar"),
         			  FALSE, FALSE, 0);
}

int main(int argc, char *argv[])
{
	string url;
	string user;
	string pass;
	string database;

	if (argc >= 2) url=argv[1]; else url=EXAMPLE_HOST;
	if (argc >= 3) user=argv[2]; else user=EXAMPLE_USER;
	if (argc >= 4) pass=argv[3]; else pass=EXAMPLE_PASS;
	if (argc >= 5) database=argv[4]; else database=EXAMPLE_DB;

	driver = get_driver_instance();
	/* Using the Driver to create a connection */
	con = driver->connect(url, user, pass);
	con->setSchema(database);
	/* Creating a "simple" statement - "simple" = not a prepared statement */
	stmt = con->createStatement();

    gtk_init (&argc, &argv);

      GtkWidget *bar;
      GtkWidget *label;

      entry1 = gtk_entry_new ();
      gtk_entry_set_text (GTK_ENTRY (entry1), EXAMPLE_QUERY_1);
      entry2 = gtk_entry_new ();
      gtk_entry_set_text (GTK_ENTRY (entry2), EXAMPLE_QUERY_2);

      /* create window, etc */
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_title (GTK_WINDOW (window), "MySQLBrowser");
      gtk_container_set_border_width (GTK_CONTAINER (window), 5);
      g_signal_connect (window, "destroy",
                        G_CALLBACK (gtk_widget_destroyed), &window);

      vbox = gtk_vbox_new (FALSE, 5);

      add_menu();

      bar = gtk_info_bar_new ();
      gtk_box_pack_start (GTK_BOX (vbox), bar, FALSE, FALSE, 0);
      gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING);
      label = gtk_label_new ("You may edit the cells below!");
      gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0);

      sw = gtk_scrolled_window_new (NULL, NULL);

      gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
                                           GTK_SHADOW_ETCHED_IN);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
                                      GTK_POLICY_AUTOMATIC,
                                      GTK_POLICY_AUTOMATIC);
      gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);

      gtk_container_add (GTK_CONTAINER (window), vbox);

      gtk_window_set_default_size (GTK_WINDOW (window), 320, 200);

  if (!gtk_widget_get_visible (window))
    gtk_widget_show_all (window);
  else
    {
      gtk_widget_destroy (window);
      window = NULL;
    }

	gtk_main();
	return 0;
}
